package nezumi.gui;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

import nezumi.state.State;

public abstract class AGui extends Canvas {
	/** The strategy that allows us to use accelerate page flipping */
	protected final BufferStrategy strategy;

	/** The list of all the entities that exist in our game */
	protected final List<IEntity> entities = new ArrayList<IEntity>();
	protected final Dimension canvasSize;
	protected final State state;
	protected final int sleepTime;

	/**
	 * Construct our GUI and set it running.
	 */
	public AGui(String name, Dimension canvasSize, State state, int refreshRate) {

		assert name != null : "name = " + name;
		assert canvasSize != null : "canvasSize = " + canvasSize;
		assert state != null : "state =" + state;
		assert refreshRate > 0 : "refreshRate = " + refreshRate;

		this.state = state;
		this.canvasSize = canvasSize;
		this.sleepTime = refreshRate;
		
		// create a frame to contain our game
		JFrame container = new JFrame(name);

		// get hold the content of the frame and set up the resolution of the
		// game

		final JPanel panel = (JPanel) container.getContentPane();
		panel.setPreferredSize(canvasSize);
		panel.setLayout(null);

		// setup our canvas size and put it into the content of the frame
		setBounds(0, 0, canvasSize.width, canvasSize.height);
		panel.add(this);

		// Tell AWT not to bother repainting our canvas since we're
		// going to do that our self in accelerated mode
		setIgnoreRepaint(true);

		// finally make the window visible
		container.pack();
		container.setResizable(false);
		container.setVisible(true);

		// add a listener to respond to the user closing the window. If they
		// do we'd like to exit
		container.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		// request the focus so key events come to us
		requestFocus();

		// create the buffering strategy which will allow AWT
		// to manage our accelerated graphics
		createBufferStrategy(2);
		this.strategy = getBufferStrategy();

		// initialize the entities so there's something
		// to see at startup
		initEntities();
	}

	/**
	 * Initialize the starting state of the entities (ship and aliens). Each
	 * entity will be added to the overall list of entities.
	 */
	protected abstract void initEntities();

	/**
	 * The main GUI loop. Its main purpose is to update the screen with new
	 * information.
	 * <p>
	 */
	public void guiLoop() {

		// keep looping
		while (true) {

			// Get hold of a graphics context for the accelerated
			// surface and blank it out
			final Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
			g.setColor(Color.GRAY);
			g.fillRect(0, 0, canvasSize.width, canvasSize.height);

			// cycle round drawing all the entities we have, in order
			for (IEntity entity : entities)
				entity.draw(g);

			// finally, we've completed drawing so clear up the graphics
			// and flip the buffer over
			g.dispose();
			strategy.show();

			// finally pause for a bit. Note: this should run us at about
			// 20 FPS but on windows this might vary each loop due to
			// a bad implementation of timer
			try {
				Thread.sleep(sleepTime);
			} catch (Exception e) {
			}
		}
	}
}
